package com.yzkj.siot.facade.impl;

import cn.hutool.core.lang.UUID;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yzkj.siot.cache.SysSettingCache;
import com.yzkj.siot.context.CurUserCtx;
import com.yzkj.siot.domain.TenantDevice;
import com.yzkj.siot.domain.TenantProduct;
import com.yzkj.siot.domain.TenantProductData;
import com.yzkj.siot.exp.BizExp;
import com.yzkj.siot.facade.ProductDataFacade;
import com.yzkj.siot.facade.ProductFacade;
import com.yzkj.siot.facade.SysDictFacade;
import com.yzkj.siot.result.PageParams;
import com.yzkj.siot.result.PageResponse;
import com.yzkj.siot.service.SysDictService;
import com.yzkj.siot.service.TenantDeviceService;
import com.yzkj.siot.service.TenantProductDataService;
import com.yzkj.siot.service.TenantProductService;
import com.yzkj.siot.util.PageHelper;
import com.yzkj.siot.vo.ProductVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ProductFacadeImpl implements ProductFacade {

    @Autowired
    TenantProductService productService;

    @Autowired
    TenantDeviceService deviceService;

    @Autowired
    TenantProductDataService productDataService;

    @Autowired
    ProductDataFacade productDataFacade;

    @Autowired
    PageHelper<TenantProduct> productPageHelper;


    @Override
    public PageResponse<ProductVO> page(PageParams<TenantProduct> pageParams) {

        TenantProduct where = pageParams.getEntity();
        QueryWrapper<TenantProduct> productQueryWrapper = new QueryWrapper<>();

        if (where != null) {
            productQueryWrapper.lambda()
                    .like(!StringUtils.isEmpty(where.getUniqueCode()), TenantProduct::getUniqueCode, where.getUniqueCode())
                    .like(!StringUtils.isEmpty(where.getProductName()), TenantProduct::getProductName, where.getProductName())
                    .eq(where.getStatus() != null, TenantProduct::getStatus, where.getStatus())
                    .eq(where.getDataBase() != null && where.getDataBase() != 0, TenantProduct::getDataBase, where.getDataBase())
            ;
        }
        pageParams.getOrderBy().forEach(item -> productQueryWrapper.orderBy(true, item.getIsAsc(), item.getField()));

        PageResponse<TenantProduct> productPageResponse = productPageHelper.queryPageOrList(productService.getBaseMapper(), pageParams, productQueryWrapper);
        List<ProductVO> records = new ArrayList<>();
        for (TenantProduct item : productPageResponse.getRecords()) {
            records.add(new ProductVO(item, SysSettingCache.dict));
        }

        return new PageResponse<>(productPageResponse, records);

    }

    @Override
    public ProductVO queryOne(int id) {

        TenantProduct product = productService.getById(id);

        if (product == null) {
            return null;
        }

        QueryWrapper<TenantProductData> productDataQueryWrapper = new QueryWrapper<>();
        productDataQueryWrapper.lambda().eq(TenantProductData::getProductId, id);

        product.setProductDataList(productDataService.list(productDataQueryWrapper));

        return new ProductVO(product, SysSettingCache.dict);
    }

    @Transactional
    @Override
    public ProductVO saveOrUpdate(TenantProduct entity) {

        // 若是需要更新，校验是否存在此id的产品
        if (entity.getId() != null && entity.getId() != 0 && productService.getById(entity.getId()) == null) {
            throw new BizExp("此产品不存在或已被删除!");
        }

        // 校验重名
        QueryWrapper<TenantProduct> productQueryWrapper = new QueryWrapper<>();
        productQueryWrapper.lambda()
                .eq(TenantProduct::getProductName, entity.getProductName())
                .ne(TenantProduct::getId, entity.getId());

        if (productService.count(productQueryWrapper) != 0) {
            throw new BizExp("已存在同名产品！");
        }

        // 生成32位唯一编码
        if (entity.getId() == null || entity.getId() == 0) {
            entity.setTenantId(CurUserCtx.get().getTenantId());
            String uniqueCode = UUID.fastUUID().toString(true);
            entity.setUniqueCode(uniqueCode);
        }

        if (!productService.saveOrUpdate(entity)) {
            throw new BizExp("保存产品时出现未知错误！");
        }


        // 数据解析协议
        // 需要删除的
        if (entity.getId() != null || entity.getId() != 0) {
            List<TenantProductData> preProductList = queryOne(entity.getId()).getProductDataList();
            List<TenantProductData> paramProductDataList = entity.getProductDataList();
            List<Integer> willRemoveList = preProductList.stream().map(TenantProductData::getId).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(willRemoveList) && !CollectionUtils.isEmpty(paramProductDataList)) {
                // 过滤出参数给过来的不是新增的解析协议的id
                List<Integer> paramProductDataIdList = paramProductDataList
                        // 过滤不是新增的
                        .stream().filter(data -> data.getId() != null && data.getId() != 0).collect(Collectors.toList())
                        // 提取id字段
                        .stream().map(TenantProductData::getId).collect(Collectors.toList());
                willRemoveList.removeAll(paramProductDataIdList);
                if (!CollectionUtils.isEmpty(willRemoveList)) {
                    willRemoveList.forEach(item -> productDataService.removeById(item));
                    log.info("删除的解析协议 ids => {}, data => {}",
                            willRemoveList,
                            preProductList.stream().filter(item -> willRemoveList.contains(item.getId())).collect(Collectors.toList()));
                }
            }
        }

        // 需要更新/新增的
        if (!CollectionUtils.isEmpty(entity.getProductDataList())) {
            entity.getProductDataList().forEach(item -> {
                item.setProductId(entity.getId());
                productDataFacade.saveOrUpdate(item);
            });
        }

        log.info("保存产品 => {} 数据解析协议 => {}", entity, entity.getProductDataList());
        return queryOne(entity.getId());
    }

    @Override
    public ProductVO remove(int id) {

        TenantProduct product = queryOne(id);

        if (product == null) {
            throw new BizExp("此产品不存在或已被删除！");
        }

        // 校验是否存在属于此产品的设备
        QueryWrapper<TenantDevice> deviceQueryWrapper = new QueryWrapper<>();
        deviceQueryWrapper.lambda().eq(TenantDevice::getProductId, id);
        if (deviceService.count(deviceQueryWrapper) != 0) {
            throw new BizExp("仍存在属于此产品的设备，不可删除！");
        }

        // 删除这个产品的数据解析项
        QueryWrapper<TenantProductData> productDataQueryWrapper = new QueryWrapper<>();
        productDataQueryWrapper.lambda().eq(TenantProductData::getProductId, id);
        if (productDataService.remove(productDataQueryWrapper)) {
            throw new BizExp("删除此产品数据解析协议时发生错误！");
        }

        if (!productService.removeById(id)) {
            throw new BizExp("删除产品时发生错误！");
        }

        return this.queryOne(id);
    }

    @Override
    public Boolean batchRemove(List<Integer> idList) {

        // 校验是否存在属于这些产品的设备
        QueryWrapper<TenantDevice> deviceQueryWrapper = new QueryWrapper<>();
        deviceQueryWrapper.lambda().in(TenantDevice::getProductId, idList);

        if (deviceService.count(deviceQueryWrapper) != 0) {
            throw new BizExp("仍存在属于这批产品的设备，不可批量删除！");
        }

        if (!productService.removeByIds(idList)) {
            throw new BizExp("删除产品时发生错误！");
        }

        return true;
    }

    @Override
    public Boolean batchSave(List<TenantProduct> entities) {
        return null;
    }
}
